package edu.xidian.sei

import java.io.{File, PrintWriter}
import scala.math.BigDecimal
import javax.swing.JFrame
import edu.xidian.sei.util.GridFrame
import scala.collection.mutable.ArrayBuffer

/** 簇 */
trait Cluster

/** 缺省簇实现 */
case class DefaultCluster(val id: Index) extends Cluster {
  var density: BigDecimal = BigDecimal(0)
  val objects = new collection.mutable.HashSet[Grid]
  var center: Array[Double] = _

  override def hashCode: Int = id.hashCode

  override def equals(obj: Any): Boolean = {
    val other = obj.asInstanceOf[DefaultCluster]
    other.id.equals(this.id)
  }

  def compute {
    center = new Array[Double](Space.getInstance.dimension)
    for (grid <- objects) {
      density += grid.density
      center = Location.twoArrayAdd(center, grid.center.dimensions)
    }
    for (i <- 0 until Space.getInstance.dimension) {
      center(i) = center(i) / objects.size
    }

  }

  def merge(other: DefaultCluster) {
    for (i <- 0 until Space.getInstance.dimension) {
      this.center(i) = (this.center(i) * this.objects.size + other.center(i) * other.objects.size) / (this.objects.size + other.objects.size)
    }
    this.density += other.density
  }
}

/** 网格匹配模式 */
trait Pattern[T] extends Function2[T, T, Boolean]

/** 匹配的两个网格的坐标 */
case class Matched(val first: Any, val second: Any)

/** 能够处理一批网格的处理器 */
trait Processor[K, V] {
  def process(keys: Iterable[K], data: collection.Map[K, V], params: collection.Map[String, Any]): Seq[Matched]
}

/** 能够处理所有数据的聚类反应堆 */
trait ClusteringReactor {
  def clustering(id: String, data: collection.Map[_, _], params: collection.Map[String, Any]): Unit

  def cleanup(): Unit
}

/** 需要一次处理的分片数据 */
case class DataToProcess[K, V](datas: collection.Map[K, V], params: collection.Map[String, Any])

/** 能够将数据进行切分的分片器 */
trait Slicer {
  def slice[K <: Index, V](data: collection.Map[K, V], params: collection.Map[String, Any]): Seq[DataToProcess[K, V]]
}

/** 报告输出者 */
trait Reporter {
  def report(result: collection.Map[Any, Cluster])
}

/** 文件报告输出者 */
class FileReporter(val fileName: String) extends Reporter {
  def report(result: collection.Map[Any, Cluster]): Unit = {
    val filewriter = new PrintWriter(new File(fileName))
    println(s"Writing ${result.size} grid to $fileName")
    val drawResult = new ArrayBuffer[(Array[Int], String)]()
    for ((k, v) <- result) {
      val gridID = k.asInstanceOf[Grid].id.dimensions
      val clusterID = v.asInstanceOf[DefaultCluster].id.asInstanceOf[Index].dimensions.mkString(",")
      filewriter.println(gridID.mkString(",") + "=>" + clusterID)

      //drawResult += (gridID -> clusterID)
    }
    filewriter.close
    //draw(drawResult, fileName)
  }

  def draw(result: ArrayBuffer[(Array[Int], String)], title: String) {
    val jf = new JFrame();
    jf.setSize(750, 750);
    jf.setVisible(true);
    jf.setDefaultCloseOperation(2);
    jf.getContentPane().add(new GridFrame(50, 15, 70, result, title))
  }
}